

#include "process.h"
#include "simulator.h"
#include "queue.h"
#include "disk.h"
#include "observer.h"

#include <stdio.h>
#include <stdlib.h>


/* in ms*/
#define DISK_ACCESS_TIME	10


void disk_die(char *);

struct qQueue *waiting;
int nextEventTime;
/* By Cliff Buchanan and Jacob Eichers
	 disk.c: Simulates the disk input and output*/

/* accept a job onto the disk queue*/
void disk_accept_job(struct process *job)
{
	int err = 0;

	if(q_is_empty(waiting))
		{nextEventTime = sim_get_clock()+DISK_ACCESS_TIME;}

	err = q_add(waiting, job);
	if(err)
		{disk_die("disk_accept_job");}

	obs_disk_accept_job(job);
}
 
/* Should be called only when disk_done()==0 and disk_time_to_event()==0.
	Returns process that has been on the disk queue the longest.*/
struct process *disk_return_job(void)
{
	struct process *p;
	
	if(!q_is_empty(waiting))
	{
		nextEventTime = sim_get_clock()+DISK_ACCESS_TIME;
		p = q_remove(waiting);
		if(!p)
			{disk_die("disk_return_job");}
	}
	else
		{p = NULL;}

	obs_disk_return_job(p);

	return p;
}

/* Returns the time until the disk is done reading.
	Undefined when disk_done()!=0*/
int disk_time_to_event(void)
{
	if(nextEventTime>sim_get_clock())
		{return nextEventTime-sim_get_clock();}
	else
		{return 0;}
}

/* Returns 0 iff the disk has no jobs left in it's queue.*/
int disk_done(void)
{
	return q_is_empty(waiting);
}

/* Setup for the simulated disk. Must be performed before any
	other calls are made.*/
void disk_init()
{
	nextEventTime = 0;
	waiting = q_create();
	if(!waiting)
		{disk_die("disk_init");}
}

void disk_die(char *caller)
{
	fprintf(stderr, "%s: critical error! Exiting...\n", caller);
	exit(-1);
}
